iT邦幫忙

2026 iThome 鐵人賽

DAY 4
0
AI Engineering

30 天拆解 Wearable × AI:從穿戴裝置生理訊號到AI健康洞察系列 第 4

Day 04|為什麼 HRV 不是越高越好?RMSSD 與 SDNN 在說什麼

  • 分享至 

  • xImage
  •  

今天為什麼研究這個?

Day 3 談完 PPG 取出心跳間隔之後,接下來就是 HRV。這應該是穿戴裝置的恢復/壓力類指標中最常被引用的,但同時也讓人感到陌生卻又容易被誤解的指標。市面上的 app 隨便抓一個HRV數據就說「你今天恢復不佳」或是「你壓力很大」,我一直很好奇這裡面到底發生了什麼事。今天會把 HRV 拆成兩個最基本的時域指標:RMSSD 與 SDNN,它們一個看逐拍差值,一個看整體離散度,但用途完全不同。為什麼 HRV 高低不代表健康,什麼情況下 HRV 會失真,又是什麼會導致數據完全錯掉?

Concept

心率變異度(HRV)測量的不是心跳速度,而是連續心跳間期的時間變化。RMSSD 與 SDNN 雖然都是以「毫秒(ms)」為單位的時域指標,但捕捉的生理訊號與時間維度截然不同。

1. 計算口徑與數學定義差異

指標 英文全名 計算口徑 反映的變異維度
RMSSD Root Mean Square of Successive Differences 相鄰 NN 間期差值(NN(i+1) − NN(i))平方和的均值開根號 逐拍差值(beat-to-beat):專注於相鄰心跳間的極短期、高頻劇烈擺動
SDNN Standard Deviation of NN intervals 整段量測期間所有正常 NN 間期的標準差 總體離散度(global dispersion):描述整段時間內心跳間期偏離平均值的整體離散程度
  • 兩個指標的字面定義都建立在 NN 上。Task Force 1996 把 NN 定義成「相鄰 QRS 之間、由竇房結去極化產生的所有間期」,也就是異常拍與雜訊已經剔除之後的序列;RR 與 NN 的差別不是標記法,是有沒有做過剔除這一步。
  • 來自ECG處理訊號的演算法鏈:R 波偵測 → R-R(所有相鄰心跳)→ 剔除非竇性拍與雜訊、處理剔除留下的斷點 → NN → RMSSD / SDNN。判準這一拍從哪裡來,不是訊號乾不乾淨——心室早發拍波形清楚、品質完美,但它不從竇房結來,一樣要剔。下面 Hands-On 被剔掉的 161 個間期就全是這種拍造成的(68 個心室早發、13 個心房早發),沒有一個是偽影。
  • 剔除也不是原地換個名字,丟掉的間期會在序列裡留下時間斷點,而跨斷點的差值已經不是「相鄰 NN 的差」。這一步做了什麼、丟了多少,跟指標值一樣屬於口徑。
  • 穿戴裝置處理訊號的演算法鏈:脈波峰偵測 → 峰間期 → 過濾偽影 → 到此為止。PPG 看得出這一拍什麼時候到,看不出它從哪裡來,竇性與否無從判定,所以濾得再乾淨也到不了 NN。這條鏈的產物該叫什麼、與 ECG 差多少,第 4 節談。
  • RMSSD 透過「逐拍相減」的微分效果,過濾掉了心率隨時間緩慢漂移的低頻趨勢,只留下瞬間的拍動跳躍。
  • SDNN 則不看相鄰兩拍的差距,而是把所有間期拉成一整個分佈算標準差,因此時間拉得越長(例如 5 分鐘 vs. 24 小時),數值差異極大,受晝夜節律與活動影響甚鉅。

2. 生理機制:各自描述哪一種變異?

RMSSD(副交感神經/迷走神經的即時鏡子)

心臟的迷走神經釋放乙醯膽鹼,作用時間極短(數十毫秒內即可啟動與終止),能在單次心跳之間迅速調節心率(如呼吸性竇性心律不整 RSA)。交感神經的反應慢(經由正腎上腺素傳導,需數秒才有反應),無法造成逐拍劇烈變化。因此,RMSSD 是目前臨床與穿戴裝置評估副交感(迷走神經)張力最常用的指標。

SDNN(自律神經總輸出與動態調控能力)

包含了副交感神經的高頻跳動、交感神經的慢速拉升、體溫調節、神經內分泌(如腎上腺素)以及 24 小時晝夜節律的總和。SDNN 描述的是整體自律神經系統適應內外環境變化的總儲備量,標準的臨床評估通常基於 24 小時動態心電圖(Holter)。

3. 為什麼「HRV 越高越好」是錯誤框架?

許多人把 HRV 當成「遊戲分數」,誤以為數值無上限衝高代表越健康,這忽略了生理與量測兩邊的限制:

  1. 心律不整與傳導異常的偽高訊號:心房顫動(AFib)、頻繁的心室早期收縮(PVC)或心房早期收縮(PAC),會造成心跳間期極度混亂。演算法若未完全剔除異常拍,算出來的 RMSSD 與 SDNN 會飆到異常高值,但這代表的是心臟傳導病態,而非自主神經健康。
  2. 跨人比高低這件事本身就不成立:Nunan 2010 回顧 44 篇研究、21,438 位健康成人,發現個體之間的 HRV 差異大到 260,000%(主要出現在頻域指標),而且各研究對 RR 的剔除與編修方式不同,本身就讓數值彼此對不上。

4. 手錶上顯示的 HRV,其實是 PRV

一般入門消費型穿戴裝置沒有 ECG。它拿到的是 PPG 脈波的峰到峰間隔(pulse cycle interval),由此算出的變異性,正確的名稱是 PRV(pulse rate variability)。Schäfer & Vagedes 2013 回顧 PPG 與 ECG 的對照研究,結論是靜止時 PRV 的準確度足夠,但短期變異會被略微高估,來源是呼吸與心血管系統的耦合效應;而在身體活動與部分心理壓力下,PRV 與 HRV 的一致性明顯變差。

那為什麼顯示出來的還是叫 HRV?我想到兩層原因:

  • 使用條件剛好落在誤差可接受的那一段。 消費裝置多半只在睡眠或靜止時算這個數字,而那正是 Schäfer 說「準確度足夠」的條件。在這個前提下叫它 HRV,失真有限。
  • 名字是沿用來的,不是量出來的。 HRV 在使用者、文獻與平台 API 裡都是既有詞彙,PRV 沒有這個認知基礎,改名的成本全落在廠商身上而好處落在讀者身上。這一層我沒有來源,是推論。

Hands-on

Dataset

今天要釘的是口徑,而口徑的核心是。NN要判斷一拍從不從竇房結來,得看得到 R 波形態,手錶給不了這個。所以今天刻意用 ECG 導出的間期:先在看得見波形的資料上把定義講清楚,Day 9 再拿 PPG-DaLiA 的雙通道去量手錶那條鏈到底差多少。

PhysioNet 的 Normal Sinus Rhythm RR Interval Database(nsr2db),54 筆長時間紀錄,13 MB。檔案不是現成的間期表,而是 WFDB beat annotation(.ecg)加表頭(.hea);ANNOTATORS 寫的是 "corrected beat annotations from an automated detector"——自動偵測後再人工校正,不是原始 ECG,也不是無誤的真值。每一拍都帶 annotation code(N 竇性、V 心室早發、A 心房早發),要不要剔除是讀的人自己決定——名字裡的 RR 指的是它給你未剔除的完整序列,下面的 R-R 與 NN 兩條線都是從同一個檔案產生的。取樣率 128 Hz,間期解析度 1000/128 = 7.8125 ms,正是 Task Force 提到的 "approximately 8 ms (precisely 7.8125 ms=1/128 seconds)";nsr001 的十萬多個間期,每一個都落在這個格點上。另一半資料是合成的:變異型態已知、兩個指標可以用紙筆算出來的短序列。

Method

  1. 造兩條 n=20 的序列,母體 SD 都設成 30 ms:一條逐拍一長一短,一條單調漂移。RMSSD 的期望值是解析解(2d 與步長 d / sqrt((n²−1)/12)),不是跑完再抄回來。
  2. 在乾淨序列中間插一個縮短 40% 的間期、後接代償性長間期,總時長不變,刻意不剔除。
  3. 讀 nsr001,一次取所有相鄰心跳(R-R),一次只取兩端都是竇性搏動的(NN)。
  4. 同一筆資料切成 5 分鐘視窗各算一次,跟 22.55 小時的全段比。

SDNN 的標準差用 ddof=1。Task Force 只寫 "the square root of variance",沒指定母體或樣本,n=20 時兩者差 2.6%——這種選擇不記下來,同一個函式名就會產出兩種數字。

Code

from wearable_ai.datasets.physionet_rr import load_rr
from wearable_ai.hrv import rmssd, sdnn
from wearable_ai.synthetic import alternating_rr, ramp_rr

alt = alternating_rr(20, mean_ms=1000, sd_ms=30)   # 逐拍一長一短
ramp = ramp_rr(20, mean_ms=1000, sd_ms=30)         # 單調漂移,母體 SD 相同
sdnn(alt), sdnn(ramp)      # (30.78, 30.78)
rmssd(alt), rmssd(ramp)    # (60.00, 5.20)

rr = load_rr("nsr001")                     # 所有相鄰心跳:R-R
nn = load_rr("nsr001", normal_only=True)   # 兩端都是竇性搏動:NN

https://ithelp.ithome.com.tw/upload/images/20260917/20184206DC0DLI8puJ.png

上圖兩條線的離散程度一樣,下圖差了一個數量級。RMSSD 看的就是下圖。

跑出來的數字

資料 SDNN(ms) RMSSD(ms)
逐拍交替 ±30 ms(n=20) 30.78 60.00
緩慢漂移,同樣的 SD(n=20) 30.78 5.20
乾淨序列(n=300) 20.18 29.36
同一條,插入一個早發拍 37.79 62.56
nsr001 全段 R-R(22.55 h,106,459 個間期) 168.65 34.33
nsr001 全段 NN(剔掉 161 個,0.15%) 168.54 32.10
nsr001 的 5 分鐘視窗(270 段的中位數) 49.66 25.09
  • 300 拍裡錯一拍,兩個指標都接近翻倍(SDNN +87%、RMSSD +113%)。序列越長倍數越小,n=1200 時是 1.31× 與 1.43×。所以「一個異常拍就足以讓指標失效」成立,「RMSSD 特別脆弱」不成立。
  • R-R 換成 NN,SDNN 幾乎不動(−0.10 ms),RMSSD 掉 2.23 ms。nsr001 只有 81 個非竇性搏動,算是乾淨的一筆:53 筆(排除缺表頭的 nsr042)的剔除比例中位數 0.102%,而最大的 nsr024 是 15.90%——一個叫「正常竇性心律」的資料庫,有一筆要丟掉六分之一的間期。
  • 只改視窗長度,SDNN 從 49.66 變成 168.65,全段是 5 分鐘中位數的 3.4 倍。

https://ithelp.ithome.com.tw/upload/images/20260917/20184206IPV8OF0gXd.png

結果與意外

原本以為 實際發現
HRV 不能跨人比,是因為基因與年齡的差異 文獻能直接支持的是另一件事:各研究對 RR 的剔除與編修方式不同,數值本身就對不上(Nunan 2010,44 篇研究、21,438 人)。個人基準是不是更好的參考,留到 Day 15
手錶上顯示的 HRV 就是 HRV 那是 PPG 峰間期算出來的 PRV。靜止時夠接近,但短期變異會被高估,活動與部分心理壓力下一致性明顯變差(Schäfer & Vagedes 2013)

Limitations

  1. NN 那條序列有 161 個洞,我沒有補。 剔掉非竇性拍會在序列裡留下時間斷點,32.10 ms 是跨著這些斷點算出來的,嚴格說已經不是「相鄰 NN 的差」。Task Force 只在頻域那段(1048 頁)要求內插,沒有替時域規定斷點怎麼處理——分段是我從定義推出來的做法,留到 Day 10。
  2. 早發拍縮短 40%,是我挑的數字。 真實的 PVC 與 PAC 在提前多少、代償多少上變化很大,我沒有查到分佈。那組倍數只說明方向與量級,不是臨床值。
  3. 128 Hz 這件事,Task Force 會皺眉。 原文建議 250–500 Hz,100 Hz 以上只有在對 R 波定位點做拋物線內插精修時才算堪用,而資料庫沒說標註流程有沒有做過。RMSSD 是差分,量化階梯會直接進到結果裡:7.8125 ms 的格點就是今天所有數字的誤差下限。
  4. ECG 挑得出 NN,是因為它看得到波形。 手錶只有脈波峰間期,濾掉體動偽影不等於篩掉非竇性拍。第 4 節那條鏈就斷在這裡,今天的做法搬不過去。
  5. 一筆紀錄、一個人、22.55 小時。 全段與 5 分鐘視窗的數字都來自 nsr001,而且視窗那組用的是未剔除的 R-R、最後一段不滿 300 秒也算進去了。它撐得起的只有「視窗長度會動搖 SDNN」(49.66 → 168.65,3.4 倍)這一件事,不能拿去跟文獻常模或手錶的夜間平均對比。

這對 AI Engineering 的意義

今天的數字都指向同一件事:一個指標值,不帶口徑就沒有意義

hrv_rmssd_ms = 32.10 這個欄位背後至少有四個開關:間期來自 R 波還是 PPG 脈波峰、有沒有剔除非竇性搏動、視窗是 5 分鐘還是 24 小時、標準差用 ddof=0 還是 1。四個都不在欄位名裡,而幅度差很大:視窗長度能讓 SDNN 差 3.4 倍,一個沒剔掉的異常拍能讓 n=300 的 RMSSD 變 2.1 倍,ddof 的差則只有 2.6%——最小的那個一樣沒人記,而它一樣會讓兩支程式對同一段訊號給出不同的數字。LLM 不會問這是哪種口徑,它會直接拿去跟參考區間比、跟昨天比、跟別人比——今天的資料顯示,口徑不同時這三種比較全部無效。

所以 feature contract 要帶的不只是數值與單位,還有 sourcewindow_sbeat_filterddof 與被剔除的比例。Task Force 1048 頁的要求就是這件事的臨床版:被剔除與內插的間期,數量與時長佔比都要一併報告。三十年前的共識文件把口徑寫進報告裡,今天的裝置把它藏在一個名詞後面。

另一件是別把變異壓成一個分數。逐拍交替與緩慢漂移的 SDNN 完全相同,生理意義卻不同,而被壓掉的正是 LLM 最需要用來判斷的結構。


上一篇
Day 03|PPG 如何從皮膚上的光,看見心跳?
下一篇
Day 05|每晚一個 HRV 數字是怎麼來的?從 5 分鐘視窗到 nightly metric
系列文
30 天拆解 Wearable × AI:從穿戴裝置生理訊號到AI健康洞察10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言